//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.WebClient
{
    using System;
    using System.Globalization;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Windows.Browser;
    using Microsoft.Research.ScientificWorkflow.TridentModelSL;
    using Microsoft.Research.ScientificWorkflow.WebClient.Common;
    using Microsoft.Research.ScientificWorkflow.WebClient.Views;
    using Microsoft.Research.ScientificWorkflow.WorkflowApplicationCommonSL;
    using Microsoft.Research.eResearch;

    /// <summary>
    /// Manages the trident web client and initializes all the view in the application
    /// </summary>
    public class TridentApplication
    {
        private static TridentApplication application;

        private string loggedUserName;
        private string loggedUserDisplayName;
        private string applicationTitle;
        private string subtitle;
        private string hostUri;
        private UserModel loggedinUser;
        private UserRole userRole;
        private MainWindow window;
        private IView toolBarView;
        private IView navigationView;
        private IView workAreaView;

        /// <summary>`
        /// Initializes a new instance of the <see cref="TridentApplication"/> class.
        /// </summary>
        private TridentApplication()
        {

        }

        static TridentApplication()
        {
            RegistryService.LoadUserCompleted += new EventHandler<LoadUserCompletedEventArgs>(OnLoadUserCompleted);
        }

        #region Properties

        /// <summary>
        /// Gets the instance of the Trident application
        /// </summary>
        /// <value>The instance.</value>
        public static TridentApplication Instance
        {
            get
            {
                if (application == null)
                {
                    application = new TridentApplication();
                }
                return application;
            }
        }

        /// <summary>
        /// Gets the host URI.
        /// </summary>
        /// <value>The host URI.</value>
        public string HostUri
        {
            get
            {
                return this.hostUri;
            }
        }

        /// <summary>
        /// Gets the title of the browser.
        /// </summary>
        /// <value>The title.</value>
        public string Title
        {
            get
            {
                return this.applicationTitle;
            }
            private set
            {
                this.applicationTitle = value;
                HtmlPage.Document.SetProperty("title", this.applicationTitle);
            }
        }

        /// <summary>
        /// Gets or sets the sub title of the browser.
        /// </summary>
        /// <value>The sub title.</value>
        public string Subtitle
        {
            get
            {
                return this.subtitle;
            }
            set
            {
                this.subtitle = value;
                HtmlPage.Document.SetProperty("title", string.Format(CultureInfo.CurrentCulture, "{0} - {1}", this.applicationTitle, this.subtitle)); ;
            }
        }

        /// <summary>
        /// Gets or sets the status message.
        /// </summary>
        /// <value>The status message.</value>
        public string StatusMessage
        {
            get
            {
                return this.window.StatusMessage;
            }
            set
            {
                this.window.StatusMessage = value;
            }
        }

        /// <summary>
        /// Gets the user.
        /// </summary>
        /// <value>The user.</value>
        public UserModel User
        {
            get
            {
                return this.loggedinUser;
            }
        }

        /// <summary>
        /// Gets the name of the logged in user.
        /// </summary>
        /// <value>The name of the user.</value>
        public string UserName
        {
            get
            {
                return this.loggedUserName;
            }
        }

        /// <summary>
        /// Gets the display name of the user.
        /// </summary>
        /// <value>The display name of the user.</value>
        public string UserDisplayName
        {
            get
            {
                return this.loggedUserDisplayName;
            }
        }

        /// <summary>
        /// Gets the user role.
        /// </summary>
        /// <value>The user role.</value>
        public UserRole UserRole
        {
            get
            {
                return userRole;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is authenticated.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is authenticated; otherwise, <c>false</c>.
        /// </value>
        public bool IsAuthenticated
        {
            get
            {
                return (this.loggedUserName == Constants.AnonymousUserName ? false : true);
            }
        }
        #endregion

        /// <summary>
        /// Loads the specified application.
        /// </summary>
        /// <param name="applicationName">Name of the application.</param>
        public void Load(string applicationName)
        {
            string clientName = applicationName.ToUpper(CultureInfo.InvariantCulture);
            //TODO: Check for the client access permission
            this.window = new MainWindow();
            App.Current.RootVisual = this.window;

            switch (clientName)
            {
                case "COMPOSER":
                    break;
                case "MANAGEMENTSTUDIO":
                    break;
                case "WORKFLOWAPPLICATION":
                    this.Title = "Workflow Application";

                    this.navigationView = new Views.WorkflowApplication.NavigationView();
                    this.workAreaView = new Views.WorkflowApplication.WorkAreaView();
                    this.toolBarView = new Views.WorkflowApplication.ToolbarView();

                    this.Initialize();
                    break;
                default:
                    //TODO: Show unknown screen
                    break;
            }
        }

        private void Initialize()
        {
            userRole = UserRole.Admin;
            this.hostUri = HtmlPage.Document.DocumentUri.OriginalString.Substring(0, HtmlPage.Document.DocumentUri.OriginalString.LastIndexOf(Constants.UriSeparator, StringComparison.InvariantCulture));
            string webServiceUri = new Uri(HtmlPage.Document.DocumentUri, Constants.WebServicePageName).OriginalString;
            Binding serviceBinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
            EndpointAddress endPoint = new EndpointAddress(webServiceUri);

            WebHostServiceReference.GetWebServiceSoapClient serviceClient = new WebHostServiceReference.GetWebServiceSoapClient(serviceBinding, endPoint);
            serviceClient.GetWebServiceURICompleted += delegate(object sender, WebHostServiceReference.GetWebServiceURICompletedEventArgs e)
            {
                RegistryService.Initialize(new Uri(e.Result));
                this.LoadUserInfo();
            };

            serviceClient.GetWebServiceURIAsync();
        }

        private static void OnLoadUserCompleted(object sender, LoadUserCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.User != null)
                {
                    TridentApplication.Instance.loggedinUser = e.User;
                    TridentApplication.Instance.userRole = e.User.Role;
                    TridentApplication.Instance.InitializeViews();
                }
                else
                {
                    HtmlPage.Window.Alert(WorkflowApplicationResources.UserProfileNotExists);
                    TridentApplication.Instance.LogOff();
                }
            }
            else
            {
                HtmlPage.Window.Alert(e.Error.Message);
            }

        }

        /// <summary>
        /// Initializes the views.
        /// </summary>
        private void InitializeViews()
        {
            this.window.LoadViews(this.toolBarView, this.navigationView, this.workAreaView);
        }

        /// <summary>
        /// Gets the name of the logged user.
        /// </summary>
        private void LoadUserInfo()
        {
            HtmlElement userNameElement = HtmlPage.Document.GetElementById("tbxUserName");
            if (userNameElement != null)
            {
                this.loggedUserName = userNameElement.GetProperty("value").ToString();

            }
            HtmlElement userDisplayNameElement = HtmlPage.Document.GetElementById("tbxDisplayName");
            if (userDisplayNameElement != null)
            {
                this.loggedUserDisplayName = userDisplayNameElement.GetProperty("value").ToString();
            }

            RegistryService.LoadUserAsync(this.UserName);
        }

        public void LogOff()
        {
            try
            {
                HtmlPage.Window.Invoke(Constants.JavaScriptClearAuthCache);

                Uri targetUri = new Uri(this.hostUri + Constants.UriSeparator + Constants.SignOutPageName, UriKind.Absolute);
                HtmlPage.Window.Navigate(targetUri);
            }
            catch (InvalidOperationException) { }
            catch (Exception) { }
        }
    }
}
